package com.yxx.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.yxx.annotation.VisitLogger;
import com.yxx.entity.VisitLog;
import com.yxx.manager.AsyncManager;
import com.yxx.manager.factory.AsyncFactory;
import com.yxx.utils.IpUtils;
import com.yxx.utils.UserAgentUtils;
import lombok.val;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;


/**
 * AOP记录访问日志
 * @author yuxiangxun
 * @date 2025/2/14
 * @apiNote
 */
@Component
@Aspect
public class VisitLogAspect {

    @Pointcut("@annotation(com.yxx.annotation.VisitLogger)")
    public void visitLogPointCut(){}

    /**
     * 后置通知
     * 连接点正常返回通知，拦截用户操作日志，正常执行完成后执行
     * 如果连接点抛出异常，则不会执行
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "visitLogPointCut()" , returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result){
        // 从切入点处通过反射机制获取切入点处的方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = methodSignature.getMethod();
        // 通过方法获取注解
        VisitLogger visitLogger = method.getAnnotation(VisitLogger.class);
        // 获取 request 操作 通过 当前请求的上下文信息 获取 当前请求的 RequestAttributes 对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        // 根据 ServletRequestAttributes 获取当前请求的 request 对象
        HttpServletRequest request = Objects.requireNonNull(servletRequestAttributes).getRequest();

        String ipAddress = ServletUtil.getClientIP(request);
        String ipSource = IpUtils.getIpSource(ipAddress);
        // 解析browser和os
        Map<String, String> userAgentMap = UserAgentUtils.parseOsAndBrowser(request.getHeader("User-Agent"));
        // 获取到的日志保存到数据库  -> 新建VisitLog()对象，封装数据后进行插入数据库操作
        VisitLog visitLog = new VisitLog();
        // 封装数据
        visitLog.setPage(visitLogger.value());
        visitLog.setIpAddress(ipAddress);
        visitLog.setIpSource(ipSource);
        visitLog.setOs(userAgentMap.get("os"));
        visitLog.setBrowser(userAgentMap.get("browser"));
        // 保存到数据库
        AsyncManager.getInstance().execute(AsyncFactory.recordVisit(visitLog));
    }

}
